﻿/**
 * Licensed under the MIT License
 *
 * Copyright (c) 2010 Laurent Berthelot
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package marcel.display.draw.shapes
{
	import flash.display.Graphics;
	import flash.geom.Rectangle;
	import marcel.display.draw.props.EllipseProps;
	import marcel.display.draw.props.FillProps;
	import marcel.display.draw.props.LineProps;
	
	
	/**
	 * The EllipseShape class contains a static method that you can use to draw an ellipse shape.
	* @author Laurent Berthelot
	*/
	public class EllipseShape extends BasicShape
	{
		//--------------------------------------------------------------------------
		//
		//  Pubic static vars
		//
		//--------------------------------------------------------------------------
		/**
		 * Angle of circle in radians.
		 */
		static public var CIRCLE:Number = Math.PI * 2;
		/**
		 * Angle of half circle in radians.
		 */
		static public var HALF_CIRCLE:Number = Math.PI;
		/**
		 * Angle of quater circle in radians.
		 */
		static public var QUARTER_CIRCLE:Number = Math.PI * .5;
		
		//--------------------------------------------------------------------------
		//
		//  Private static vars
		//
		//--------------------------------------------------------------------------
		static private var _PRECISION:Number = Math.PI / 32;
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		/**
		 * Non-instanciable class, only statics methods in EllipseShape class.
		 */
		public function EllipseShape(o:ConstructorAccess) {}
		
		//--------------------------------------------------------------------------
		//
		//  Public static methods
		//
		//--------------------------------------------------------------------------
		/**
		 * Draws an ellipse.
		 * @param	graphics	Graphics object to draw on.
		 * @param	ep			Ellipse properties.
		 * @param	fp			Fill properties.
		 * @param	lp			Line style properties.
		 */
		static public function drawShape(graphics:Graphics, ep:EllipseProps = null, fp:FillProps = null, lp:LineProps = null):Graphics
		{
			var segs:int = Math.ceil(ep.angle/_PRECISION);
			if (segs <= 0) return graphics;
			_lineStyle(graphics, lp);
			_beginFill(graphics, fp, new Rectangle( -ep.radius.x, -ep.radius.x, ep.radius.x * 2, ep.radius.y * 2));
			var theta:Number = -ep.angle/segs;
			var angle:Number = 0;
			var startAngle:Number = 0;
			var bx:Number, by:Number, cy:Number, cx:Number;
			var i:int;
			var ob:Object = new Object();
			var ax:Number = Math.cos(startAngle / 180 * Math.PI) * ep.radius.x;
			var ay:Number = Math.sin( -startAngle / 180 * Math.PI) * ep.radius.y;
			graphics.moveTo(ep.radiusInner.x, 0);
			(ep.angle < 2 * Math.PI)? graphics.lineTo(ax, ay) : graphics.moveTo(ax, ay);
			for (i = 0; i < segs; i++) {
				angle += theta;
				ob = _getBezier(angle, theta, 0, 0, ep.radius.x, ep.radius.y, -1);
				graphics.curveTo(ob.cx, ob.cy, ob.bx, ob.by);
			}
			var ex:Number = Math.cos(angle) * ep.radiusInner.x;
			var ey:Number = Math.sin(angle) * ep.radiusInner.y;
			(ep.angle < 2 * Math.PI)? graphics.lineTo(ex, ey) : graphics.moveTo(ex, ey);
			if (ep.radiusInner.x > 0) {
				for (i = 0; i < segs; i++) {
					angle -= theta;
					ob = _getBezier(angle, theta, 0, 0, ep.radiusInner.x, ep.radiusInner.y, 1);
					graphics.curveTo(ob.cx, ob.cy, ob.bx, ob.by);
				}
			}
			_endFill(graphics);
			return graphics;
		}
		
		//--------------------------------------------------------------------------
		//
		//  Private static methods
		//
		//--------------------------------------------------------------------------
		static private function _getBezier(a:Number, t:Number, sx:Number, sy:Number, rx:Number, ry:Number, dir:Number):Object {
			var bx:Number, by:Number, cy:Number, cx:Number;
			var angleMid:Number = a + dir * (t * .5);
			var o:Object = new Object();
			o.bx = sx + Math.cos(a) * rx;
			o.by = sy + Math.sin(a) * ry;
			o.cx = sx + Math.cos(angleMid) * (rx / Math.cos(t * .5));
			o.cy = sy + Math.sin(angleMid) * (ry / Math.cos(t * .5));
			return o;
		}

	}
}
internal class ConstructorAccess {}